package com.chigga.application.hanlder.login.username;

import com.chigga.common.utils.JSON;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import java.io.IOException;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 用户名密码登录/身份认证过滤器
 *
 * @author DefChigga
 */
@Slf4j
public class UsernameAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

     // private static final Logger logger = LoggerFactory.getLogger(UsernameAuthenticationFilter.class);

    public UsernameAuthenticationFilter(AntPathRequestMatcher pathRequestMatcher, AuthenticationManager authenticationManager, AuthenticationSuccessHandler authenticationSuccessHandler, AuthenticationFailureHandler authenticationFailureHandler) {
        super(pathRequestMatcher);
        super.setAuthenticationManager(authenticationManager);
        super.setAuthenticationSuccessHandler(authenticationSuccessHandler);
        super.setAuthenticationFailureHandler(authenticationFailureHandler);
    }

    /**
     * 尝试身份验证
     * AbstractAuthenticationProcessingFilter 的实现类 attemptAuthentication 要做的工作：
     * 1. 从HttpServletRequest提取授权凭证。假设用户使用 用户名/密码 登录，就需要在这里提取username和password。
     * 然后，把提取到的授权凭证封装到的Authentication对象，并且authentication.isAuthenticated()一定返回false
     * 2. 将Authentication对象传给AuthenticationManager进行实际的授权操作
     * @param request 请求
     * @param response 响应
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        log.debug("use UsernameAuthenticationFilter");

        // 提取请求数据
        String requestJsonData = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
        Map<String, Object> requestMapData = JSON.parseToMap(requestJsonData);
        String username = requestMapData.get("username").toString();
        String password = requestMapData.get("password").toString();

        // 封装成Spring Security需要的对象
        UsernameAuthentication authentication = new UsernameAuthentication();
        authentication.setUsername(username);
        authentication.setPassword(password);
        // 认证不通过，这里一定要设成false
        authentication.setAuthenticated(false);

        // 开始登录认证。SpringSecurity会利用 Authentication对象去寻找 AuthenticationProvider进行登录认证
        return super.getAuthenticationManager().authenticate(authentication);
    }
}
